home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
THINKC
/
4_0
/
GNUUCP_2
/
SOURCE
/
SYSDEP.UNI
< prev
next >
Wrap
Text File
|
1989-07-31
|
13KB
|
577 lines
/*
* @(#)sysdep.unix 1.11 87/09/29 Copyright 1987 Free Software Foundation, Inc.
*
* Copying and use of this program are controlled by the terms of the
* GNU Emacs General Public License.
*/
#ifndef lint
char sysdep_version[] = "@(#)sysdep.unix gnuucp Version hoptoad-1.11";
#endif
#ifdef BSD
/* Unix Berserkeley systems */
#include <stdio.h>
#include <ctype.h>
#include <sgtty.h>
#include <sys/param.h>
#include <sys/file.h>
#include <sys/time.h>
#include <signal.h>
#include <setjmp.h>
#include <strings.h>
#include <sys/dir.h>
#define dirent direct /* For POSIX compatability */
extern char *strtok();
#define UNIX
#define NAMESIZE MAXPATHLEN
#endif
#ifdef SYSV
/* Unix System V */
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <termio.h>
#include <signal.h>
#include <setjmp.h>
#include <string.h>
#include <dirent.h> /* SVR3 -- older has to use PD version */
#define UNIX
#endif
#include "uucp.h"
#include "sysdep.h"
/* Stuff common to all Unix systems */
#define STDIN 0
#define CONTROL "/usr/lib/uucp/gnuucp.ctl"
#define O_BINARY 0 /* No distinction between text and binary */
/*
* Exported variables
*/
char sysdep_control[] = CONTROL;
/* Our variables */
static jmp_buf alarming; /* For read timeouts */
#ifdef BSD
struct sgttyb atermio, btermio;
#endif
#ifdef SYSV
struct termio atermio, btermio;
#endif
int fdtty; /* File descriptor for tty line */
void sigint(); /* Forward declaration */
/*
* Translation between integer baud rates and Unix baud rates (grumble)
*/
static struct baudtab {
int baudrate, damn_B_code;
} baudtab[] = {
50, B50,
75, B75,
110, B110,
134, B134,
150, B150,
200, B200,
300, B300,
600, B600,
1200, B1200,
1800, B1800,
2400, B2400,
4800, B4800,
9600, B9600,
19200, B19200,
38400, B38400,
};
static int
damn_B(baud)
{
register struct baudtab *b;
for (b = baudtab; b->baudrate < baud; b++) continue;
if (b->baudrate == baud)
return b->damn_B_code;
return EXTB; /* Maybe this'll get clocking from the modem */
}
/*
* Open the serial line for an incoming call.
* Argument of NULL or empty string means stdin.
*/
int
openline(ttynam, baud)
char *ttynam;
int baud;
{
int ontheline = !(ttynam && ttynam[0]); /* FIXME, this is garbage */
#ifdef BSD
/* Berserkeley version */
if (ontheline) {
fdtty = STDIN;
} else if ((fdtty = open(ttynam, O_RDWR)) < 0) {
if (DEBUG_LEVEL(0)) perror(ttynam);
exit(1);
}
ioctl(fdtty, TIOCGETP, &atermio);
btermio = atermio;
btermio.sg_flags |= RAW;
btermio.sg_flags &= ~(ECHO|XTABS);
if (!ontheline)
btermio.sg_ispeed = btermio.sg_ospeed = damn_B(baud);
ioctl(fdtty, TIOCSETN, &btermio);
signal(SIGINT,sigint);
#endif
#ifdef SYSV
/* Missed'em Five version */
if (ontheline) {
fdtty = STDIN;
} else if ((fdtty = open(ttynam, O_RDWR)) < 0) {
if (DEBUG_LEVEL(0)) perror(ttynam);
exit(1);
}
ioctl(fdtty,TCGETA,&atermio);
btermio = atermio;
btermio.c_iflag = btermio.c_oflag = btermio.c_lflag = 0;
btermio.c_cc[VMIN] = 1;
btermio.c_cc[VTIME] = 0;
if (!ontheline)
btermio.c_cflag = (btermio.c_cflag & ~CBAUD) | damn_B(baud);
ioctl(fdtty,TCSETA,&btermio);
#endif
signal(SIGINT,sigint);
signal(SIGTERM,sigint);
return SUCCESS;
}
/*
* Open the serial line for an outgoing call.
*/
int
openout(ttynam, baud)
char *ttynam;
int baud;
{
char devname[PORTNAME_SIZE*2+SLOP];
/* Set cleanup monitor */
signal(SIGINT, sigint);
signal(SIGTERM, sigint);
/* Lock against several uucp's trying to use the same line */
if (ttylock(ttynam) != SUCCESS)
return FAIL;
sprintf(devname, "/dev/%s", ttynam);
#ifdef BSD
/* Berserkeley version */
if ((fdtty = open(devname, O_RDWR)) < 0) {
if (DEBUG_LEVEL(0)) perror(devname);
ttyunlock();
return FAIL;
}
ioctl(fdtty, TIOCGETP, &atermio);
btermio = atermio;
btermio.sg_flags |= RAW;
btermio.sg_flags &= ~(ECHO|XTABS);
btermio.sg_ispeed = btermio.sg_ospeed = damn_B(baud);
ioctl(fdtty, TIOCSETN, &btermio);
#endif
#ifdef SYSV
/* Missed'em Five version */
if ((fdtty = open(devname, O_RDWR)) < 0) {
if (DEBUG_LEVEL(0)) perror(devname);
return FAIL;
}
ioctl(fdtty,TCGETA,&atermio);
btermio = atermio;
btermio.c_iflag = btermio.c_oflag = btermio.c_lflag = 0;
btermio.c_cc[VMIN] = 1;
btermio.c_cc[VTIME] = 0;
btermio.c_cflag = (btermio.c_cflag & ~CBAUD) | damn_B(baud);
ioctl(fdtty,TCSETA,&btermio);
#endif
return SUCCESS;
}
/*
* Basement level I/O routines
*
* xwrite() writes a character string to the serial port
* xgetc() returns a character from the serial port, or an EOF for timeout.
* sigint() restores the state of the serial port on exit.
* hangup() hangs up the serial port (e.g. drop DTR).
*/
void
sigint()
{
logit("INTERRUPTED", "terminating");
hangup();
exit(0);
}
/* Real simple for Unix */
xwrite(buf,ctr)
char *buf;
int ctr;
{
return write(fdtty, buf, ctr);
}
/*
* Serial port reading routines
*/
sigalrm()
{
longjmp(alarming, 1);
}
/*
* FIXME: This is really slow; it does 4 system calls per byte!
*/
int
xgetc()
{
char data;
int status;
signal(SIGALRM,sigalrm);
alarm(BYTE_TIMEOUT);
if (setjmp(alarming) == 0)
{
status = read(fdtty,&data,1);
alarm(0);
if (status == 1) /* the read worked, returning 1 char */
return(data & 0xFF);
}
/* Error on serial port, or timeout. */
return(EOF);
}
/*
* hangup(): hang up the 'fone.
*/
int
hangup()
{
/* Restore terminal settings on dialout line */
#ifdef BSD
ioctl(fdtty, TIOCSETN, &atermio);
#endif
#ifdef SYSV
ioctl(fdtty,TCSETA,&atermio);
#endif
if (0 != close(fdtty)) {
if(DEBUG_LEVEL(0)) perror("closing tty");
}
ttyunlock();
sleep(2); /* To be sure DTR stays down that long */
}
/*
* Create a temporary file name for receiving a file into.
* "name" is the name we will actually eventually want to use for the file.
* We currently ignore it, but some OS's that can't move files around
* easily might want to e.g. put the temp file into the same directory
* that this file is going into.
*
* FIXME:
* This interface should be able to return a "possible" filename, and
* be re-called if the name is already in use, to get another.
* This avoids checking here whether the name is good -- saving system calls.
*/
char *
temp_filename(name)
register char *name;
{
static char tname[NAMESIZE];
static int count = 0;
if (ourpid == 0)
ourpid = getpid();
(void) sprintf(tname, "TM.u%d.%d", ourpid, count++);
DEBUG(7, "Using temp file %s\n", tname);
return tname;
}
/*
* Transform a filename from a uucp packet (in Unix format) into a local
* filename that will work in the local file system.
*/
char *
munge_filename(name)
register char *name;
{
register char *p;
static char buffer[NAMESIZE+SLOP];
int len, hostlen;
DEBUG(7, "Munge_filename input: %s\n", name);
/* FIXME: Security checking goes here! */
if (name[0] == '~') {
/* Handle user-relative names -- ~ or ~uucp turns to Pubdir */
if (name[1] == '/')
p = &name[1];
else if (!strncmp("~uucp/", name, 6))
p = &name[5];
else {
p = NULL; /* Neither of the above */
goto out;
}
strcpy(buffer, Pubdir);
strcat(buffer, p);
p = buffer;
goto out;
}
#ifdef SUBDIR
/* Berkeley Unix subdirectory hack.
* Full pathnames go through OK.
* D.myname* -> D.myname/D.myname*
* D.* -> D./D.*
* C.* -> C./C.*
* LCK.* -> LCK..*
* otherwise left alone (e.g. X.*, STST.*).
* FIXME: I hear Honey Danber has a slightly different scheme.
* In particular, STST's go in a directory.
*/
if (name[0] != '/') {
if (name[1] == '.' &&
(name[0] == 'C' || name[0] == 'D')) {
len = strlen(name);
hostlen = strlen(Myname);
if (hostlen > 7) hostlen = 7;
/* Check D.mynameAxxxx case */
if (name[0] == 'D' && len == hostlen + 2 + 5 &&
!strncmp(&name[2], Myname, hostlen))
len = 2 + hostlen; /* "D."+name */
else
len = 2; /* Just "D." */
strcpy(buffer, name);
buffer[len] = '/';
strcpy(buffer+len+1, name);
p = buffer;
goto out;
}
if (strncmp("LCK.", name, 4) == 0 &&
strcmp("LCK.XQT", name) != 0) {
/* For some reason, old uucp uses "LCK..xxx" rather
* than "LCK.xxx". Except for LCK.XQT. Foo.
*/
strcpy(buffer, "LCK..");
strcpy(buffer+5, name+4);
p = buffer;
goto out;
}
}
#endif
p = name; /* Let it through as-is. */
out:
DEBUG(7, "Munge_filename output: %s\n", p);
return p;
}
/*
* Uucp work queue scan.
*
* gotsome = work_scan(hostname, type);
* workfile = work_next();
* void work_done();
*/
/*
* Local variables of the work queue scanner -- not visible to outsiders
*
* Workhost and worktype are always null-terminated; keeping their lengths
* is just a performance hack. Workprefix is NOT null terminated; various
* people copy things after it and use the whole string. Workprefix is
* exactly workplen long; to append something, strcpy(workprefix+workplen, ...)
*/
#define MAX_TYPE 10
static DIR *workdir = (DIR *)NULL;
static struct dirent *workfile;
static char workhost[MAX_HOST+1];
static int workhlen;
static char worktype[MAX_TYPE+1];
static int worktlen;
static char workfirst = 0;
/* FIXME, at the moment this can be local to work_scan() */
static char workprefix[MAX_TYPE+1+MAX_HOST+1+MAX_TYPE+1+MAX_HOST+6+SLOP];
/* D . hoptoad / D . hoptoad N1234\0 */
static int workplen;
void
work_done()
{
if (workdir)
closedir(workdir);
workdir = (DIR *) NULL;
workfile = (struct dirent *) NULL;
workfirst = 0;
}
int
work_scan(host, type)
char *host;
char *type;
{
char *p;
if (!host)
host = "";
/* If called twice in a row, don't thrash the disk again */
if (strcmp(workhost, host) == SAME &&
strcmp(worktype, type) == SAME && workfile)
return 1;
if (workdir) work_done(); /* Clean up prev call */
workfirst = 1; /* Initialize for work_next */
workhlen = strlen(host);
if (workhlen > sizeof (workhost) -1) abort();
strcpy(workhost, host);
if (workhlen > 7) workhlen = 7; /* Unix uucp limit */
worktlen = strlen(type);
if (worktlen > sizeof (worktype) -1) abort();
strcpy(worktype, type);
/* Figure out which subdirectory this class of files is in. */
/* FIXME: doesn't handle "all D. files" since D.myname is separate. */
sprintf(workprefix, "%s.%s", worktype, workhost);
p = munge_filename(workprefix);
strcpy(workprefix, p);
p = index(workprefix, '/');
if (p)
workplen = 1 + p - workprefix; /* Prefix ends after '/' */
else
workplen = 0; /* No / in munged; hence no dir */
workprefix[workplen] = '\0';
DEBUG(8, "Work prefix is =%s=\n", workprefix);
strcpy(workprefix+workplen, ".");
workdir = opendir(workprefix); /* Open whatever directory */
if (workdir == NULL) {
DEBUG(0, "Can't open queue directory %s\n", workprefix);
return 0; /* No work */
}
return work_look();
}
static int
work_look()
{
int len;
for (;;) {
workfile = readdir(workdir);
if (workfile == NULL) {
DEBUG(7, "work_look: end of dir\n", 0);
work_done();
return 0; /* No work */
}
DEBUG(8, "work_look readdir %s\n", workfile->d_name);
/* Is it the right type? */
if (strncmp(workfile->d_name, worktype, worktlen) == SAME
&& workfile->d_name[worktlen] == '.') {
/* see if it matches the hostname */
len = strlen(workfile->d_name);
/* "C" "." "hoptoad" "Xnnnn" */
if (workhlen == 0 ||
(len == worktlen + 1 + workhlen + 5 &&
!strncmp(workhost, workfile->d_name+2, workhlen))
) {
/* Found an entry! */
/* FIXME, check grade letter! */
DEBUG(7, "work_look found %s\n", workfile->d_name);
return 1; /* Found work */
}
}
}
/* NOTREACHED */
}
char *
work_next()
{
static char buffer[NAMESIZE+SLOP];
if (!workfirst) {
if (!workfile || !work_look())
return (char *)NULL;
}
workfirst = 0;
if (strncmp("LCK..", workfile->d_name, 5) == 0) {
/*
* For some reason, old uucp uses "LCK..xxx" rather
* than "LCK.xxx" like it does everywhere else.
* We return the "LCK.xxx" form.
*/
strcpy(buffer, "LCK.");
strcpy(buffer+4, workfile->d_name+5);
return buffer;
}
return workfile->d_name;
}
/*
* Routine to return a string that gives the current date and time, and
* identifies the current process, if on a multiprocess system.
*/
char *
time_and_pid()
{
long clock;
struct tm *tm;
static char format[] = "%d/%d-%d:%02d:%02d-%d";
static char outbuf[sizeof(format)];
(void) time(&clock);
tm = localtime(&clock);
if (ourpid == 0)
ourpid = getpid();
sprintf(outbuf, format,
tm->tm_mon+1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec,
ourpid);
return outbuf;
}